#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>


//预处理详解
/**
* 1.预定义符号
* C语言设置了一些预定义符号，可以直接使用，预定义符号也是在预处理期间处理的
* 1.__FILE__  //进行编译的源文件的路径名字
* 2.__LINE__  //文件当前的行号
* 3.__DATE__  //文件被编译的日期
* 4.__TIME__  //文件被编译的时间
* 5.__STDC__  //如果编译器完全遵循ANSI C，其值是1，否则未定义
*
*/
//
//int main()
//{
//	printf("%s\n", __FILE__);
//	printf("%s\n", __DATE__);
//	printf("%s\n", __TIME__);
//	printf("%d\n", __LINE__);
//
//	return 0;
//}


/**
* #define 定义常量
*/
//#define MAX 1000
//#define reg register
//#define do_forever for(;;)
//#define CASE break;case
//int main()
//{
//	int input = 0;
//	scanf("%d", &input);
//	switch (input)
//	{
//		break;case 1:
//		printf("a");
//		case 2:
//		printf("b");
//	}
//	return 0;
//}
//#define DEBUG_PRINT printf("file:%s\tline:%d\t\
//date:%s\ttime:%s\n",\
//__FILE__,__LINE__,__DATE__,__TIME__)
////如果定义的Stuff太长，可以分几行写，除了最后一行外，每行的后面都加一个反斜杠(续行符)
//int main()
//{
//	DEBUG_PRINT;
//	return 0;
//}

//不要在#define后面加;
//#define MAX 10000
//int main()
//{
//	printf("%d\n", MAX);//如果#define MAX 10000后面有;则err
//	return 0;
//}

//#define MAX 10000;
//
//int main()
//{
//	int input = 0;
//	int max = 0;
//	scanf("%d", &input);
//	if (input)
//		max = MAX;//err
//  //max = MAX后面加了;，等替换之后，if和else之间就是2条语句，而没有大括号的时候，if后边就只能有一条语句，所有err
// 
//	else
//		max = 0;
//	return 0;
//}

//#define 定义宏
//#define机制包括了一个规定，允许把参数替换到文本中，这种实现通常成为宏或者定义宏
//宏的申明方式：
//#define name(parament_list) stuff
//注意：参数列表的左括号必须与name紧邻

//#define SQUARE(x) x * x
//int main()
//{
//	int a = 5;
//	int ret = SQUARE(a);
//	//纯粹的文本替换 int ret = a * a
//	//printf("%d\n", ret);
//	printf("%d\n", SQUARE(a + 1));
//	//结果是11，不符合预期
//	//纯粹的文本替换 printf("%d\n",a + 1 * a + 1);
//	//可以在宏定义中给加上两个括号
//	return 0;
//}
//
//#define SQU(x) (x) * (x)
//
//int main()
//{
//	int a = 5;
//	printf("%d\n", SQU(a + 1));
//
//	return 0;
//}

//还有一个宏定义
//#define DOUBLE1(x) (x) + (x)
//#define DOUBLE2(x) ( (x) + (x) )
//int main()
//{
//	int a = 5;
//	printf("%d\n", 10 * DOUBLE1(a));
//	//与预期不符
//	//printf("%d\n",10 * a + a);
//	//所以应该在宏定义表达式两边加上一对括号即可
//	printf("%d\n", 10 * DOUBLE2(a));
//	return 0;
//}

//总结，进行宏定义的时候，不要吝啬括号

//带有副作用的宏参数在使用的时候就可能出现危险，导致不可预测的后果

//#define MAX(a,b) ((a) > (b) ? (a) : (b))

//int main()
//{
//	int x = 5;
//	int y = 2;
//	int z = MAX(x, y);
//	printf("%d\n", z);
//	return 0;
//}

//int main()
//{
//	int x = 5;
//	int y = 2;
//	int z = MAX(x++, y++);
//	printf("%d\n", z);
//	printf("%d\n", x);
//	printf("%d\n", y);
//	return 0;
//}

//宏和函数的对比
//宏常应用于简单的运算
//
//#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
//
//int max(int x, int y)
//{
//	int r = (x > y) ? x : y;
//	return r;
//}
//
//int main()
//{
//	int a = 5.2;
//	int b = 3;
//	printf("%f\n", MAX(3.2, 6.4));
//	printf("%d\n", max(a, b));
//	return 0;
//}

//1.
// 函数：1.调用函数 2.使用函数 3.返回函数
// 宏：执行运算
//2.
//函数的参数必须声明为特定的类型，宏的参数与类型无关

//宏的参数可以出现类型
//#define Malloc(n,type) (type*)malloc(n*sizeof(type))
//#include <stdlib.h>
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//
//	int* ptr = Malloc(10,int);
//	return 0;
//}

//int main()
//{
//	printf("hello world\n");
//	printf("hello ""world\n");
//	return 0;
//}

//#运算符
//#运算符将宏的一个参数转换为字符串字面量，仅允许出现在带参数的宏的替换列表中

//#define Print(n, format)    printf("the value of "#n " is "format"\n", n)
//#define PRINT(n, format)    printf("the value of"#n " is " format"\n", n)
//int main()
//{
//	int a = 10;
//	int b = 20;
//	int c = 30;
//	float t = 50.5f;
//
//	Print(a, "%d");
//	PRINT(b, "%d");
//	PRINT(t, "%f");
//
//	return 0;
//}

//#define Print(n,format) printf("the value of "#n " is "format"\n", a )
//
//int main()
//{
//	int a = 1;
//	Print(a, "%d");
//	printf("the value of a is %d\n", a);
//
//	int b = 20;
//	printf("the value of b is %d\n", b);
//
//	float f = 5.6f;
//	printf("the value of f is %f\n", f);
//
//	return 0;
//}


//int int_max(int x, int y)
//{
//	return (x > y) ? x : y;
//}
//
//float float_max(float x, float y)
//{
//	return (x > y) ? x : y;
//}
//
//
//int main()
//{
//	int r1 = int_max(3, 5);
//	printf("%d\n", r1);
//
//	float r2 = float_max(3.1f, 4.5f);
//	printf("%f\n", r2);
//
//	return 0;
//}


//##运算符
//##可以把位于它两边的符号合成一个符号，链接的两个必须是一个合法的标识符
//找一个模板，批量创造一系列函数
//
//#define GENERIC_MAX(type)      \
//type type##_max(type x, type y)   \
//{                         \
//    return x > y ? x : y;    \
//}
//
//GENERIC_MAX(int)
//
//int main()
//{
//    int r1 = int_max(3, 5);
//    printf("%d\n", r1);
//
//    return 0;
//}


//命名约定
//宏和函数的适用语法很相似
//用来区分二者：
//宏的名字全部大写
//函数名不要全大写


//undef用来移除一个宏定义
//#define MAX 1000
//
//int main()
//{
//	printf("%d\n", MAX);
//#undef MAX
//	//printf("%d\n", MAX);//C2065: “MAX”: 未声明的标识符
//
//	return 0;
//}


//条件编译
//调试性的代码，删除可惜，保留碍事
//#include <stdio.h>
//#define __DEBUG__//开关
//
//int main()
//{
//	int i = 0;
//	int arr[10] = { 0 };
//	for (i = 0; i < 10; i++)
//	{
//		arr[i] = i;
//#ifdef __DEBUG__
//		printf("%d\n", arr[i]);//为了观察数组是否赋值成功
//#endif
//	}
//	return 0;
//}

//常见的条件编译指令

//#define M 50
//int main()
//{
//#if M > 20
//	//if后面加常量表达式，常量表达式由预处理器求值
//	printf("M>20\n");
//#endif
//	return 0;
//}
//

//2.多个分支的条件编译
//#define M 10
//
//int main()
//{
//#if M == 20
//	printf("M == 20\n");
//#elif M == 10
//	printf("M == 10\n");
//#else
//	printf("无M\n");
//#endif
//	
//	return 0;
//}

//3.
//判断是否被定义
//#define __DEBUG__

//int main()
//{
//#ifdef __DEBUG__
//	printf("heh\n");
//#endif
//	return 0;
//}

//
//int main()
//{
//#if defined __DEBUG__
//	printf("hehe\n");
//#endif
//
//#if !defined __CCC__
//	printf("CCC\n");
//#endif
//	return 0;
//}


//4.嵌套指令
//#define __DEBUF__
//int main()
//{
//#ifdef __DEBUF__
//	printf("__DEBUF__");
//#if M == 20
//	printf("M == 20");
//#endif
//#endif
//	return 0;
//}

//头文件的包含
//本地头文件包含""
//""查找策略：先在源文件的所在目录下查找，如果该头文件没有找到，编译器就像查找库函数头文件一样在标准位置查找头文件
//<>直接在标准路径下去查找，如果找不到就报编译错误


//嵌套文件包含
//#include指令可以使另一个文件被编译

#include "add.h"
#include "add.h"
#include "add.h"
#include "add.h"
#include "add.h"
int main()
{
	int x = 5;
	int y = 6;
	int z = Add(x, y);
	printf("%d\n", z);
	return 0;
}
//直接这样写，预处理后代码量会巨增
//怎么解决头文件被重复引入的问题？ 答案：条件编译
//在写头文件的时候













